package crp.core.resource.domain.services;

import crp.core.resource.domain.events.ResourcePublicized;
import crp.core.resource.domain.models.Attachment;
import crp.core.resource.domain.models.CourseResourceEntity;
import crp.core.resource.domain.models.CreateCourseResourceCommand;
import crp.core.resource.domain.models.ResourceEntity;
import crp.core.resource.domain.repositories.CourseResourceRepository;
import crp.core.resource.domain.repositories.ResourceRepository;
import crp.core.shared.LifecycleStatus;
import crp.core.shared.PublicStatus;
import crp.core.shared.PublishStatus;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.transaction.Transactional;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@ApplicationScoped
public class ResourceEditor {
    private final Event<ResourcePublicized> resourcePublicizedEvent;
    private final ResourceRepository resourceRepository;
    private final CourseResourceRepository courseResourceRepository;

    @Inject
    public ResourceEditor(Event<ResourcePublicized> resourcePublicizedEvent,
                          ResourceRepository resourceRepository,
                          CourseResourceRepository courseResourceRepository) {
        this.resourcePublicizedEvent = resourcePublicizedEvent;
        this.resourceRepository = resourceRepository;
        this.courseResourceRepository = courseResourceRepository;
    }

    public ResourceEntity create(CreateCourseResourceCommand command) {
        ResourceEntity resource = new ResourceEntity();
        resource.setName(command.getName());
        Attachment attachment = new Attachment();
        attachment.setType(command.getType());
        attachment.setItems(command.getItems());
        resource.setAttachment(attachment);
        resource.setSpace(command.getSpace());
        resource.setStartAt(command.getStartAt());
        resource.setEndAt(command.getEndAt());
        resource.setPublicStatus(PublicStatus.PRIVATE);
        resource.setPublishStatus(PublishStatus.NO_PUBLISHED);
        resource.setSourceType(command.getSourceType());
        resource.setStatus(LifecycleStatus.ENABLED);
        resourceRepository.persist(resource);

        CourseResourceEntity courseResource = new CourseResourceEntity();
        courseResource.setResource(resource);
        courseResource.setCourse(command.getCourse());
        courseResourceRepository.persist(courseResource);
        return resource;
    }

    @Transactional
    public void delete(String id) {
        courseResourceRepository.deleteByResourceId(id);
        resourceRepository.deleteById(id);
    }

    @Transactional
    public void update(String id, Consumer<ResourceEntity> consumer) {
        resourceRepository.findByIdOptional(id).ifPresent(entity -> {
            consumer.accept(entity);
            resourceRepository.persist(entity);
        });
    }

    public void publish(String id) {
        resourceRepository.findByIdOptional(id).ifPresent(entity -> {
            entity.setPublishStatus(PublishStatus.PUBLISHED);
            resourceRepository.persist(entity);
        });
    }

    public void unPublish(String id) {
        resourceRepository.findByIdOptional(id).ifPresent(entity -> {
            entity.setPublishStatus(PublishStatus.NO_PUBLISHED);
            resourceRepository.persist(entity);
        });
    }

    public void publicize(String id) {
        resourceRepository.findByIdOptional(id).ifPresent(entity -> {
            entity.setPublicStatus(PublicStatus.PUBLIC);
            resourceRepository.persist(entity);
            resourcePublicizedEvent.fire(ResourcePublicized.builder()
                    .resourceId(entity.getId())
                    .build());
        });
    }

    public void unPublicize(String id) {
        resourceRepository.findByIdOptional(id).ifPresent(entity -> {
            entity.setPublicStatus(PublicStatus.PRIVATE);
            resourceRepository.persist(entity);
        });
    }

    public void enable(String id) {
        resourceRepository.findByIdOptional(id).ifPresent(entity -> {
            entity.setStatus(LifecycleStatus.ENABLED);
            resourceRepository.persist(entity);
        });
    }

    public void disable(String id) {
        resourceRepository.findByIdOptional(id).ifPresent(entity -> {
            entity.setStatus(LifecycleStatus.DISABLED);
            resourceRepository.persist(entity);
        });
    }

    public void batchPublish(List<String> ids) {
        resourceRepository.persist(resourceRepository.findByIds(ids)
                .filter(entity -> !PublishStatus.PUBLISHED.equals(entity.getPublishStatus()))
                .peek(entity -> entity.setPublishStatus(PublishStatus.PUBLISHED)).collect(Collectors.toSet()));
    }

}
